<?php declare(strict_types=1);
/**
 * @author      xianganyall <xianganyall@gmail.com>
 * @copyright   2023-2025 owner
 **/

namespace Srv\Libs\Tools;

class Des
{
    public const DES_KEY_SIZE               = 8;                // KEY字符串长度
    public const DES_OUTPUT_BASE64          = 'BASE64';         // BASE64
    public const DES_OUTPUT_HEX             = 'HEX';            // HEX
    public const DES_METHOD_ECB             = 'DES-ECB';        // ECB
    public const DES_METHOD_CBC             = 'DES-CBC';        // CBC

    /**
     * @param string $string
     * @param string $key
     * @param string $output
     * @param bool $result
     * @return string
     * 加密ECB
     */
    public static function encrypt(string $string, string $key, string $output = self::DES_OUTPUT_HEX, bool &$result = false):string
    {
        return self::encryptDes($result, $string, $key, $output, self::DES_METHOD_ECB, '', OPENSSL_RAW_DATA);
    }

    /**
     * @param string $encrypt
     * @param string $key
     * @param string $output
     * @param bool $result
     * @return string
     * 解密ECB
     */
    public static function decrypt(string $encrypt, string $key, string $output = self::DES_OUTPUT_HEX, bool &$result = false):string
    {
        return self::decryptDes($result, $encrypt, $key, $output, self::DES_METHOD_ECB, '', OPENSSL_RAW_DATA);
    }

    /**
     * @param string $string
     * @param string $key
     * @param string $output
     * @param string $iv
     * @param bool $result
     * @return string
     * 加密CBC
     */
    public static function encryptCBC(string $string, string $key, string $output = self::DES_OUTPUT_HEX, string $iv = '', bool &$result = false):string
    {
        return self::encryptDes($result, $string, $key, $output, self::DES_METHOD_CBC, $iv, OPENSSL_RAW_DATA);
    }

    /**
     * @param string $encrypt
     * @param string $key
     * @param string $output
     * @param string $iv
     * @param bool $result
     * @return string
     * 解密CBC
     */
    public static function decryptCBC(string $encrypt, string $key, string $output = self::DES_OUTPUT_HEX, string $iv = '', bool &$result = false):string
    {
        return self::decryptDes($result, $encrypt, $key, $output, self::DES_METHOD_CBC, $iv, OPENSSL_RAW_DATA);
    }

    /**
     * @param bool $result
     * @param string $string
     * @param string $key
     * @param string $output
     * @param string $method
     * @param string $iv
     * @param int $options
     * @return string
     * 加密
     */
    private static function encryptDes(bool &$result, string $string, string $key, string $output, string $method, string $iv, int $options):string
    {
        $result         = false;
        if(strlen($key) < 1) $key = sha1($string);
        $key            = self::getText($key, self::DES_KEY_SIZE);
        if(strlen($key) !== self::DES_KEY_SIZE) return '';
        if($method === self::DES_METHOD_ECB){
            $iv         = '';
        }else{
            $iv         = self::getText($iv.$key, self::DES_KEY_SIZE);
            if(strlen($iv) !== self::DES_KEY_SIZE) return '';
        }
        $encrypt        = @openssl_encrypt($string, $method, $key, $options, $iv);
        if(!is_string($encrypt) || strlen($encrypt) < 1) return '';
        $result         = true;
        if($output === self::DES_OUTPUT_BASE64){
            return base64_encode($encrypt);
        }else if($output === self::DES_OUTPUT_HEX){
            return bin2hex($encrypt);
        }
        return $encrypt;
    }

    /**
     * @param bool $result
     * @param string $encrypt
     * @param string $key
     * @param string $output
     * @param string $method
     * @param string $iv
     * @param int $options
     * @return string
     * 解密
     */
    private static function decryptDes(bool &$result, string $encrypt, string $key, string $output, string $method, string $iv, int $options):string
    {
        $result         = false;
        $key            = self::getText($key, self::DES_KEY_SIZE);
        if(strlen($key) !== self::DES_KEY_SIZE) return '';
        if($method === self::DES_METHOD_ECB){
            $iv         = '';
        }else{
            $iv         = self::getText($iv.$key, self::DES_KEY_SIZE);
            if(strlen($iv) !== self::DES_KEY_SIZE) return '';
        }
        if($output === self::DES_OUTPUT_BASE64){
            $encrypt    = base64_decode($encrypt);
        }else if($output === self::DES_OUTPUT_HEX){
            $encrypt    = hex2bin($encrypt);
        }
        if(!is_string($encrypt) || strlen($encrypt) < 1) return '';
        $string         = @openssl_decrypt($encrypt, $method, $key, $options, $iv);
        if(!is_string($string) || strlen($string) < 1) return '';
        $result         = true;
        return $string;
    }

    /**
     * @param string $text
     * @param int $length
     * @return string
     * 获取截取长度
     */
    private static function getText(string $text, int $length):string
    {
        $text       = trim($text);
        $textLength = strlen($text);
        if($textLength < 1) return $text;
        if($textLength === $length){
            return $text;
        }else if($textLength > $length){
            return substr($text, 0, $length);
        }else{
            while(strlen($text) < $length) $text .= $text;
            return substr($text, 0, $length);
        }
    }
}